﻿// Decompiled with JetBrains decompiler
// Type: TaleWorlds.CampaignSystem.Issues.IssueManager
// Assembly: TaleWorlds.CampaignSystem, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: E85F8C15-4DF6-4E9C-A58A-29177E40D07A
// Assembly location: D:\steam\steamapps\common\Mount & Blade II Bannerlord\bin\Win64_Shipping_Client\TaleWorlds.CampaignSystem.dll

using Helpers;
using System;
using System.Collections.Generic;
using System.Linq;
using TaleWorlds.CampaignSystem.Actions;
using TaleWorlds.CampaignSystem.GameMenus;
using TaleWorlds.CampaignSystem.Party;
using TaleWorlds.CampaignSystem.Roster;
using TaleWorlds.CampaignSystem.Settlements;
using TaleWorlds.CampaignSystem.Settlements.Locations;
using TaleWorlds.Core;
using TaleWorlds.Library;
using TaleWorlds.Localization;
using TaleWorlds.SaveSystem;

#nullable disable
namespace TaleWorlds.CampaignSystem.Issues
{
  public class IssueManager : CampaignEventReceiver
  {
    [SaveableField(0)]
    private int _nextIssueUniqueIndex;
    public MBReadOnlyDictionary<Hero, IssueBase> Issues;
    [SaveableField(1)]
    private readonly Dictionary<Hero, IssueBase> _issues;
    [SaveableField(2)]
    private Dictionary<string, List<IssueCoolDownData>> _issuesCoolDownData;
    [CachedData]
    private Dictionary<Hero, List<PotentialIssueData>> _issueArgs;
    [SaveableField(3)]
    private List<IssueBase> _issuesWaitingForPlayerCaptivity = new List<IssueBase>();
    public const string IssueOfferToken = "issue_offer";
    public const string HeroMainOptionsToken = "hero_main_options";
    public const string IssueClassicQuestStartToken = "issue_classic_quest_start";
    public const string IssueDiscussAlternativeSolution = "issue_discuss_alternative_solution";
    private const float IssueCancelChance = 0.2f;

    internal static void AutoGeneratedStaticCollectObjectsIssueManager(
      object o,
      List<object> collectedObjects)
    {
      ((IssueManager) o).AutoGeneratedInstanceCollectObjects(collectedObjects);
    }

    protected virtual void AutoGeneratedInstanceCollectObjects(List<object> collectedObjects)
    {
      collectedObjects.Add((object) this._issues);
      collectedObjects.Add((object) this._issuesCoolDownData);
      collectedObjects.Add((object) this._issuesWaitingForPlayerCaptivity);
    }

    internal static object AutoGeneratedGetMemberValue_nextIssueUniqueIndex(object o)
    {
      return (object) ((IssueManager) o)._nextIssueUniqueIndex;
    }

    internal static object AutoGeneratedGetMemberValue_issues(object o)
    {
      return (object) ((IssueManager) o)._issues;
    }

    internal static object AutoGeneratedGetMemberValue_issuesCoolDownData(object o)
    {
      return (object) ((IssueManager) o)._issuesCoolDownData;
    }

    internal static object AutoGeneratedGetMemberValue_issuesWaitingForPlayerCaptivity(object o)
    {
      return (object) ((IssueManager) o)._issuesWaitingForPlayerCaptivity;
    }

    public IEnumerable<Hero> IssueSolvingCompanionList
    {
      get
      {
        foreach (KeyValuePair<Hero, IssueBase> issue in this.Issues)
        {
          if (issue.Value.IsSolvingWithAlternative)
            yield return issue.Value.AlternativeSolutionHero;
        }
      }
    }

    public IssueManager()
    {
      this._issues = new Dictionary<Hero, IssueBase>();
      this._issuesCoolDownData = new Dictionary<string, List<IssueCoolDownData>>();
      this._issueArgs = new Dictionary<Hero, List<PotentialIssueData>>();
      this.Initialize();
    }

    [LoadInitializationCallback]
    private void OnLoad(MetaData metaData)
    {
      this._issueArgs = new Dictionary<Hero, List<PotentialIssueData>>();
      this.Initialize();
    }

    private void Initialize()
    {
      this.Issues = this._issues.GetReadOnlyDictionary<Hero, IssueBase>();
      this.AssignIssuesToHeroes();
    }

    private void AssignIssuesToHeroes()
    {
      foreach (KeyValuePair<Hero, IssueBase> issue in this._issues)
        issue.Key.OnIssueCreatedForHero(issue.Value);
    }

    public void InitializeForSavedGame()
    {
      if (this._issuesWaitingForPlayerCaptivity == null)
        this._issuesWaitingForPlayerCaptivity = new List<IssueBase>();
      foreach (KeyValuePair<Hero, IssueBase> keyValuePair in this._issues.ToList<KeyValuePair<Hero, IssueBase>>())
      {
        IssueBase issueBase = keyValuePair.Value;
        if (issueBase == null)
        {
          this._issues.Remove(keyValuePair.Key);
        }
        else
        {
          issueBase.InitializeIssueBaseOnLoad();
          if (issueBase.IssueOwner != keyValuePair.Key)
            Debug.FailedAssert("Issue owner is not the same as key!", "C:\\Develop\\MB3\\Source\\Bannerlord\\TaleWorlds.CampaignSystem\\Issues\\IssueManager.cs", nameof (InitializeForSavedGame), 106);
        }
      }
      this.ExpireInvalidData();
    }

    public bool CreateNewIssue(in PotentialIssueData pid, Hero issueOwner)
    {
      IssueBase issue = pid.OnStartIssue(in pid, issueOwner);
      issue.StringId = "issue_" + (object) this._nextIssueUniqueIndex;
      ++this._nextIssueUniqueIndex;
      issue.AfterCreation();
      this._issues.Add(issueOwner, issue);
      issueOwner.OnIssueCreatedForHero(issue);
      if (issueOwner.PartyBelongedTo != null)
        issue.AddTrackedObject((ITrackableCampaignObject) issueOwner.PartyBelongedTo);
      CampaignEventDispatcher.Instance.OnNewIssueCreated(issue);
      return true;
    }

    public bool StartIssueQuest(Hero issueOwner)
    {
      if (this.Issues[issueOwner].StartIssueWithQuest())
        return true;
      this.Issues[issueOwner].CompleteIssueWithStayAliveConditionsFailed();
      return false;
    }

    public void DeactivateIssue(IssueBase issue)
    {
      if (issue.IssueQuest != null)
      {
        issue.IssueQuest?.CompleteQuestWithCancel();
      }
      else
      {
        issue.IssueOwner.OnIssueDeactivatedForHero();
        Campaign.Current.ConversationManager.RemoveRelatedLines((object) issue);
        if (!this.Issues.ContainsKey(issue.IssueOwner))
          return;
        this._issues.Remove(issue.IssueOwner);
      }
    }

    public void ChangeIssueOwner(IssueBase issue, Hero newOwner)
    {
      Hero issueOwner = issue.IssueOwner;
      issueOwner.OnIssueDeactivatedForHero();
      newOwner.OnIssueCreatedForHero(issue);
      issue.IssueOwner = newOwner;
      this._issues.Remove(issueOwner);
      this._issues.Add(newOwner, issue);
      CampaignEventDispatcher.Instance.OnIssueOwnerChanged(issue, issueOwner);
    }

    private void PrepareIssueArguments(Hero hero)
    {
      List<PotentialIssueData> potentialIssueDataList;
      if (this._issueArgs.TryGetValue(hero, out potentialIssueDataList))
        potentialIssueDataList.Clear();
      else
        this._issueArgs.Add(hero, new List<PotentialIssueData>());
    }

    public void AddPotentialIssueData(Hero hero, PotentialIssueData issueData)
    {
      this._issueArgs[hero].Add(issueData);
    }

    private List<PotentialIssueData> GetPotentialIssues(Hero hero) => this._issueArgs[hero];

    public List<PotentialIssueData> CheckForIssues(Hero issueOwner)
    {
      this.PrepareIssueArguments(issueOwner);
      if (!this.Issues.ContainsKey(issueOwner))
        CampaignEventDispatcher.Instance.OnCheckForIssue(issueOwner);
      return this.GetPotentialIssues(issueOwner);
    }

    public override void DailyTick()
    {
      this.ExpireInvalidData();
      List<IssueBase> issueBaseList1 = new List<IssueBase>();
      List<IssueBase> issueBaseList2 = new List<IssueBase>();
      List<IssueBase> issueBaseList3 = new List<IssueBase>();
      foreach (KeyValuePair<Hero, IssueBase> issue in this.Issues)
      {
        IssueBase issueBase = issue.Value;
        bool flag = false;
        if (issueBase.IsSolvingWithAlternative)
        {
          CampaignTime campaignTime = issueBase.AlternativeSolutionReturnTimeForTroops;
          if (campaignTime.IsPast)
          {
            if (!this._issuesWaitingForPlayerCaptivity.Contains(issueBase))
            {
              if (Hero.MainHero.IsPrisoner)
                this._issuesWaitingForPlayerCaptivity.Add(issueBase);
              else
                issueBaseList2.Add(issueBase);
            }
          }
          else
          {
            campaignTime = issueBase.AlternativeSolutionIssueEffectClearTime;
            int toDays1 = (int) campaignTime.ToDays;
            campaignTime = CampaignTime.Now;
            int toDays2 = (int) campaignTime.ToDays;
            if (toDays1 == toDays2)
              issueBase.OnAlternativeSolutionSolvedAndTroopsAreReturning();
            JournalLog journalEntry = issueBase.JournalEntries[0];
            int progress = journalEntry.CurrentProgress + 1 > journalEntry.Range ? journalEntry.Range : journalEntry.CurrentProgress + 1;
            journalEntry.UpdateCurrentProgress(progress);
          }
        }
        if (issueBase.IsOngoingWithoutQuest && !issueBase.IssueStayAliveConditions())
        {
          issueBaseList3.Add(issueBase);
          flag = true;
        }
        if (issueBase.IssueDueTime.IsPast && issueBase.IsOngoingWithoutQuest && !flag && (double) MBRandom.RandomFloat <= 0.20000000298023224)
          issueBaseList1.Add(issueBase);
      }
      foreach (IssueBase issueBase in issueBaseList2)
        issueBase.CompleteIssueWithAlternativeSolution();
      foreach (IssueBase issueBase in issueBaseList1)
        issueBase.CompleteIssueWithTimedOut();
      foreach (IssueBase issueBase in issueBaseList3)
        issueBase.CompleteIssueWithStayAliveConditionsFailed();
    }

    public override void HourlyTick()
    {
      if (!Hero.MainHero.IsPrisoner && this._issuesWaitingForPlayerCaptivity.Count > 0)
      {
        TextObject parent = new TextObject("{=l0NTCps3}As you emerge from captivity, {COMPANION.NAME} is waiting outside and greets you. {?COMPANION.GENDER}She{?}He{\\?} says {?COMPANION.GENDER}she{?}he{\\?} has returned from {?COMPANION.GENDER}her{?}his{\\?} mission with {NUMBER} {?(NUMBER > 1)}troops{?}troop{\\?} and they are all ready to rejoin your party.");
        for (int index = this._issuesWaitingForPlayerCaptivity.Count - 1; index >= 0; --index)
        {
          IssueBase item = this._issuesWaitingForPlayerCaptivity[index];
          StringHelpers.SetCharacterProperties("COMPANION", item.AlternativeSolutionHero.CharacterObject, parent);
          parent.SetTextVariable("NUMBER", item.AlternativeSolutionSentTroops.TotalManCount);
          InformationManager.ShowInquiry(new InquiryData(string.Empty, parent.ToString(), true, false, GameTexts.FindText("str_ok").ToString(), (string) null, (Action) (() =>
          {
            this._issuesWaitingForPlayerCaptivity.Remove(item);
            item.CompleteIssueWithAlternativeSolution();
          }), (Action) null), true);
        }
      }
      foreach (KeyValuePair<Hero, IssueBase> issue in this.Issues)
        issue.Value.HourlyTickWithIssueManager();
    }

    private void ExpireInvalidData()
    {
      foreach (KeyValuePair<string, List<IssueCoolDownData>> keyValuePair in this._issuesCoolDownData)
      {
        List<IssueCoolDownData> issueCoolDownDataList = new List<IssueCoolDownData>();
        foreach (IssueCoolDownData issueCoolDownData in keyValuePair.Value)
        {
          if (!issueCoolDownData.IsValid())
            issueCoolDownDataList.Add(issueCoolDownData);
        }
        foreach (IssueCoolDownData issueCoolDownData in issueCoolDownDataList)
          keyValuePair.Value.Remove(issueCoolDownData);
      }
    }

    public bool IsThereActiveIssueWithTypeInSettlement(Type type, Settlement settlement)
    {
      foreach (KeyValuePair<Hero, IssueBase> issue in this.Issues)
      {
        if (issue.Value.GetType() == type && issue.Value.IssueSettlement == settlement)
          return true;
      }
      return false;
    }

    public int GetNumOfAvailableIssuesInSettlement(Settlement settlement)
    {
      List<IssueBase> issueBaseList = new List<IssueBase>();
      int issuesInSettlement = 0;
      foreach (KeyValuePair<Hero, IssueBase> issue in this.Issues)
      {
        if ((issue.Value.IsSolvingWithAlternative || issue.Value.IsSolvingWithLordSolution ? 1 : (issue.Value.IsSolvingWithQuest ? 1 : 0)) == 0 & (issue.Value.IssueSettlement == settlement || issue.Value.IssueOwner.CurrentSettlement == settlement) && issue.Value.IssueQuest == null)
        {
          if (issue.Value.IssueStayAliveConditions())
            ++issuesInSettlement;
          else if (issue.Value.IsOngoingWithoutQuest)
            issueBaseList.Add(issue.Value);
        }
      }
      foreach (IssueBase issueBase in issueBaseList)
        issueBase.CompleteIssueWithStayAliveConditionsFailed();
      return issuesInSettlement;
    }

    public int GetNumOfActiveIssuesInSettlement(Settlement settlement, bool includeQuests)
    {
      int issuesInSettlement = 0;
      foreach (KeyValuePair<Hero, IssueBase> issue in this.Issues)
      {
        if (((issue.Value.IsSolvingWithAlternative || issue.Value.IsSolvingWithLordSolution ? 1 : (issue.Value.IsSolvingWithQuest ? 1 : 0)) & (issue.Value.IssueSettlement == settlement ? (true ? 1 : 0) : (issue.Value.IssueOwner.CurrentSettlement == settlement ? 1 : 0))) != 0 && includeQuests == (issue.Value.IssueQuest != null))
          ++issuesInSettlement;
      }
      return issuesInSettlement;
    }

    private IEnumerable<Hero> GetHeroesThatHaveIssueForSettlement(Settlement settlement)
    {
      foreach (Hero hero in (List<Hero>) settlement.HeroesWithoutParty)
      {
        if (hero.Issue != null)
          yield return hero;
      }
      foreach (MobileParty party in (List<MobileParty>) Settlement.CurrentSettlement.Parties)
      {
        foreach (TroopRosterElement troopRosterElement in party.MemberRoster.GetTroopRoster().Where<TroopRosterElement>((Func<TroopRosterElement, bool>) (x => x.Character.IsHero)))
        {
          if (troopRosterElement.Character.HeroObject.Issue != null)
            yield return troopRosterElement.Character.HeroObject;
        }
      }
    }

    public GameMenuOption.IssueQuestFlags CheckIssueForMenuLocations(
      List<Location> currentLocations,
      bool getIssuesWithoutAQuest = false)
    {
      GameMenuOption.IssueQuestFlags issueQuestFlags = GameMenuOption.IssueQuestFlags.None;
      if (Settlement.CurrentSettlement == null || !this.Issues.Any<KeyValuePair<Hero, IssueBase>>())
        return issueQuestFlags;
      foreach (Location currentLocation in currentLocations)
      {
        foreach (LocationCharacter character in currentLocation.GetCharacterList())
        {
          Hero heroObject = character.Character.HeroObject;
          if (heroObject != null && heroObject.Issue != null && (!getIssuesWithoutAQuest || heroObject.Issue?.IssueQuest == null) && (!(currentLocation.StringId != "prison") || !heroObject.IsPrisoner))
          {
            QuestBase issueQuest = heroObject.Issue.IssueQuest;
            if ((issueQuest != null ? (issueQuest.IsOngoing ? 1 : 0) : 0) != 0 || heroObject.Issue.IsSolvingWithAlternative || heroObject.Issue.IsSolvingWithLordSolution)
              issueQuestFlags |= GameMenuOption.IssueQuestFlags.ActiveIssue;
            else
              issueQuestFlags |= GameMenuOption.IssueQuestFlags.AvailableIssue;
          }
        }
      }
      return issueQuestFlags;
    }

    public override void OnQuestCompleted(QuestBase quest, QuestBase.QuestCompleteDetails detail)
    {
      foreach (KeyValuePair<Hero, IssueBase> issue in this.Issues)
      {
        if (issue.Value.IssueQuest == quest)
        {
          switch (detail)
          {
            case QuestBase.QuestCompleteDetails.Success:
              issue.Value.CompleteIssueWithQuest();
              return;
            case QuestBase.QuestCompleteDetails.Cancel:
              issue.Value.CompleteIssueWithCancel();
              return;
            case QuestBase.QuestCompleteDetails.Fail:
              issue.Value.CompleteIssueWithFail();
              return;
            case QuestBase.QuestCompleteDetails.Timeout:
              issue.Value.CompleteIssueWithTimedOut();
              return;
            case QuestBase.QuestCompleteDetails.FailWithBetrayal:
              issue.Value.CompleteIssueWithBetrayal();
              return;
            default:
              issue.Value.CompleteIssueWithQuest();
              return;
          }
        }
      }
    }

    public override void OnSettlementEntered(MobileParty party, Settlement settlement, Hero hero)
    {
      if (party != MobileParty.MainParty)
        return;
      foreach (Hero hero1 in this.GetHeroesThatHaveIssueForSettlement(Settlement.CurrentSettlement))
      {
        if (hero1.Issue.IsOngoingWithoutQuest && !hero1.Issue.IssueStayAliveConditions())
          hero1.Issue.CompleteIssueWithStayAliveConditionsFailed();
      }
    }

    public override void OnSettlementLeft(MobileParty party, Settlement settlement)
    {
      if (!this.IssueDeactivationCommonCondition(party.LeaderHero))
        return;
      party.LeaderHero.Issue.CompleteIssueWithStayAliveConditionsFailed();
    }

    public override void OnCharacterPortraitPopUpOpened(CharacterObject character)
    {
      if (!this.IssueDeactivationCommonCondition(character.HeroObject))
        return;
      character.HeroObject.Issue.CompleteIssueWithStayAliveConditionsFailed();
    }

    private bool IssueDeactivationCommonCondition(Hero hero)
    {
      return hero != null && hero.Issue != null && hero.Issue.IsOngoingWithoutQuest && !hero.Issue.IssueStayAliveConditions();
    }

    public override void OnHeroKilled(
      Hero victim,
      Hero killer,
      KillCharacterAction.KillCharacterActionDetail detail,
      bool showNotification)
    {
      if (victim.Issue == null)
        return;
      if (victim.Issue.IssueQuest != null && victim.Issue.IssueQuest.IsOngoing)
      {
        TextObject textObject = new TextObject("{=rTvWdMXF}{DIED_HERO.LINK} died and your agreement with {?DIED_HERO.GENDER}her{?}him{\\?} canceled.");
        StringHelpers.SetCharacterProperties("DIED_HERO", victim.CharacterObject, textObject);
        victim.Issue.IssueQuest.CompleteQuestWithCancel(textObject);
      }
      else
      {
        TextObject text;
        if (killer != null)
        {
          text = GameTexts.FindText("str_responsible_of_death_link_news");
          StringHelpers.SetCharacterProperties("HERO_1", killer.CharacterObject, text);
          StringHelpers.SetCharacterProperties("HERO_2", victim.CharacterObject, text);
        }
        else
        {
          text = GameTexts.FindText("str_murdered_passive_news");
          StringHelpers.SetCharacterProperties("HERO_2", victim.CharacterObject, text);
        }
        victim.Issue.CompleteIssueWithCancel(text);
      }
    }

    public override void OnSettlementOwnerChanged(
      Settlement settlement,
      bool openToClaim,
      Hero newOwner,
      Hero oldOwner,
      Hero capturerHero,
      ChangeOwnerOfSettlementAction.ChangeOwnerOfSettlementDetail detail)
    {
      if ((newOwner == null || newOwner.Clan != Clan.PlayerClan) && (oldOwner == null || oldOwner.Clan != Clan.PlayerClan))
        return;
      foreach (KeyValuePair<Hero, IssueBase> issue in this.Issues)
      {
        if (issue.Key.IsNotable)
        {
          if (issue.Value.IssueSettlement == settlement)
            issue.Value.InitializeIssueOnSettlementOwnerChange();
          if (settlement.IsFortification && issue.Value.IssueSettlement.IsVillage && issue.Value.IssueSettlement.Village.Bound == settlement)
            issue.Value.InitializeIssueOnSettlementOwnerChange();
        }
      }
    }

    public void ToggleAllIssueTracks(bool enableTrack)
    {
      foreach (KeyValuePair<Hero, IssueBase> issue in this.Issues)
        issue.Value.ToggleTrackedObjects(enableTrack);
    }

    public void AddIssueCoolDownData(Type type, IssueCoolDownData data)
    {
      string name = type.Name;
      if (!this._issuesCoolDownData.ContainsKey(name))
        this._issuesCoolDownData.Add(name, new List<IssueCoolDownData>());
      this._issuesCoolDownData[name].Add(data);
    }

    public bool HasIssueCoolDown(Type type, Hero hero)
    {
      string name = type.Name;
      bool flag = false;
      List<IssueCoolDownData> issueCoolDownDataList;
      if (this._issuesCoolDownData.TryGetValue(name, out issueCoolDownDataList))
      {
        foreach (IssueCoolDownData issueCoolDownData in issueCoolDownDataList)
        {
          if (issueCoolDownData.IsValid() && issueCoolDownData.IsRelatedTo((object) hero))
          {
            flag = true;
            break;
          }
        }
      }
      return flag;
    }

    public override void CanHaveQuestsOrIssues(Hero hero, ref bool result)
    {
      if (this.Issues.TryGetValue(hero, out IssueBase _))
      {
        result = false;
      }
      else
      {
        foreach (KeyValuePair<Hero, IssueBase> issue in this.Issues)
        {
          issue.Value.OnHeroCanHaveQuestOrIssueInfoIsRequested(hero, ref result);
          if (!result)
            break;
          if (issue.Value.IsSolvingWithAlternative && issue.Value.AlternativeSolutionHero == hero || issue.Value.CounterOfferHero == hero)
          {
            result = false;
            break;
          }
        }
      }
    }

    public override void CanHeroDie(
      Hero hero,
      KillCharacterAction.KillCharacterActionDetail causeOfDeath,
      ref bool result)
    {
      foreach (KeyValuePair<Hero, IssueBase> issue in this.Issues)
      {
        issue.Value.OnHeroCanDieInfoIsRequested(hero, causeOfDeath, ref result);
        if (issue.Value.AlternativeSolutionHero == hero)
          result = false;
        if (!result)
          break;
      }
    }

    public override void CanHeroBecomePrisoner(Hero hero, ref bool result)
    {
      foreach (KeyValuePair<Hero, IssueBase> issue in this.Issues)
      {
        issue.Value.OnHeroCanBecomePrisonerInfoIsRequested(hero, ref result);
        if (!result)
          break;
      }
    }

    public override void CanHeroMarry(Hero hero, ref bool result)
    {
      foreach (KeyValuePair<Hero, IssueBase> issue in this.Issues)
      {
        issue.Value.OnHeroCanMarryInfoIsRequested(hero, ref result);
        if (!result)
          break;
      }
    }

    public override void CanHeroEquipmentBeChanged(Hero hero, ref bool result)
    {
      foreach (KeyValuePair<Hero, IssueBase> issue in this.Issues)
      {
        issue.Value.OnHeroCanBeSelectedInInventoryInfoIsRequested(hero, ref result);
        if (!result)
          break;
      }
    }

    public override void CanHeroLeadParty(Hero hero, ref bool result)
    {
      foreach (KeyValuePair<Hero, IssueBase> issue in this.Issues)
      {
        issue.Value.OnHeroCanLeadPartyInfoIsRequested(hero, ref result);
        if (!result)
          break;
      }
    }

    public override void CanMoveToSettlement(Hero hero, ref bool result)
    {
      foreach (KeyValuePair<Hero, IssueBase> issue in this.Issues)
      {
        issue.Value.OnHeroCanMoveToSettlementInfoIsRequested(hero, ref result);
        if (!result)
          break;
      }
    }

    public override void CanBeGovernorOrHavePartyRole(Hero hero, ref bool result)
    {
      foreach (KeyValuePair<Hero, IssueBase> issue in this.Issues)
      {
        issue.Value.OnHeroCanHavePartyRoleOrBeGovernorInfoIsRequested(hero, ref result);
        if (!result)
          break;
      }
    }

    public static void FillIssueCountsPerSettlement(
      Dictionary<Settlement, int> issueCountPerSettlement)
    {
      foreach (KeyValuePair<Hero, IssueBase> issue in Campaign.Current.IssueManager.Issues)
      {
        Settlement issueSettlement = issue.Value.IssueSettlement;
        if (issueSettlement != null)
        {
          if (!issueCountPerSettlement.ContainsKey(issueSettlement))
            issueCountPerSettlement[issueSettlement] = 1;
          else
            ++issueCountPerSettlement[issueSettlement];
        }
      }
    }

    public static IEnumerable<IssueBase> GetIssuesInSettlement(
      Settlement settlement,
      bool onlyNotables = true)
    {
      foreach (Hero notable in (List<Hero>) settlement.Notables)
      {
        if (notable.Issue != null)
          yield return notable.Issue;
      }
      if (!onlyNotables)
      {
        foreach (Hero hero in (List<Hero>) settlement.HeroesWithoutParty)
        {
          if (hero.Issue != null && !hero.IsNotable)
            yield return hero.Issue;
        }
        foreach (MobileParty settlementParty in (List<MobileParty>) settlement.Parties)
        {
          for (int i = 0; i < settlementParty.MemberRoster.Count; ++i)
          {
            Hero heroObject = settlementParty.MemberRoster.GetCharacterAtIndex(i)?.HeroObject;
            if (heroObject != null && heroObject.Issue != null)
              yield return heroObject.Issue;
          }
        }
      }
    }

    public static IssueBase GetIssueOfQuest(QuestBase quest)
    {
      foreach (KeyValuePair<Hero, IssueBase> issue in Campaign.Current.IssueManager.Issues)
      {
        if (issue.Value.IssueQuest == quest)
          return issue.Value;
      }
      return (IssueBase) null;
    }

    public static void FillIssueCountsPerClan(
      Dictionary<Clan, int> issueCountPerClan,
      IEnumerable<Clan> clans)
    {
      foreach (Clan clan in clans)
      {
        int num = 0;
        foreach (Hero hero in (List<Hero>) clan.Heroes)
        {
          if (hero.Issue != null)
            ++num;
        }
        issueCountPerClan.Add(clan, num);
      }
    }
  }
}
